package com.jfinal.token;

/**
 * Created by zhangbin on 17/2/11.
 */

import com.jfinal.core.Controller;
import com.jfinal.kit.StringKit;

import java.util.*;

public class TokenManager {
    private static ITokenCache tokenCache;
    private static Random random = new Random();

    private TokenManager() {
    }

    public static void init(ITokenCache tokenCache) {
        if(tokenCache != null) {
            tokenCache = tokenCache;
            long halfTimeOut = 150000L;
            (new Timer()).schedule(new TimerTask() {
                public void run() {
                    TokenManager.removeTimeOutToken();
                }
            }, halfTimeOut, halfTimeOut);
        }
    }

    public static String createToken(Controller controller, String tokenName, int secondsOfTimeOut) {
        if(tokenCache == null) {
            String tokenId = String.valueOf(random.nextLong());
            controller.setAttr(tokenName, tokenId);
            controller.setSessionAttr(tokenName, tokenId);
            createTokenHiddenField(controller, tokenName, tokenId);
            return tokenId;
        } else {
            return createTokenUseTokenIdGenerator(controller, tokenName, secondsOfTimeOut);
        }
    }

    private static void createTokenHiddenField(Controller controller, String tokenName, String tokenId) {
        StringBuilder sb = new StringBuilder();
        sb.append("<input type=\'hidden\' name=\'").append(tokenName).append("\' value=\'" + tokenId).append("\' />");
        controller.setAttr("token", sb.toString());
    }

    private static String createTokenUseTokenIdGenerator(Controller controller, String tokenName, int secondsOfTimeOut) {
        if(secondsOfTimeOut < 300) {
            secondsOfTimeOut = 300;
        }

        String tokenId = null;
        Token token = null;
        int safeCounter = 8;

        do {
            if(safeCounter-- == 0) {
                throw new RuntimeException("Can not create tokenId.");
            }

            tokenId = String.valueOf(random.nextLong());
            token = new Token(tokenId, System.currentTimeMillis() + (long)(secondsOfTimeOut * 1000));
        } while(tokenId == null || tokenCache.contains(token));

        controller.setAttr(tokenName, tokenId);
        tokenCache.put(token);
        createTokenHiddenField(controller, tokenName, tokenId);
        return tokenId;
    }

    public static synchronized boolean validateToken(Controller controller, String tokenName) {
        String clientTokenId = controller.getPara(tokenName);
        if(tokenCache == null) {
            String token1 = (String)controller.getSessionAttr(tokenName);
            controller.removeSessionAttr(tokenName);
            return StringKit.notBlank(clientTokenId) && clientTokenId.equals(token1);
        } else {
            Token token = new Token(clientTokenId);
            boolean result = tokenCache.contains(token);
            tokenCache.remove(token);
            return result;
        }
    }

    private static void removeTimeOutToken() {
        List tokenInCache = tokenCache.getAll();
        if(tokenInCache != null) {
            ArrayList timeOutTokens = new ArrayList();
            long currentTime = System.currentTimeMillis();
            Iterator var5 = tokenInCache.iterator();

            Token token;
            while(var5.hasNext()) {
                token = (Token)var5.next();
                if(token.getExpirationTime() <= currentTime) {
                    timeOutTokens.add(token);
                }
            }

            var5 = timeOutTokens.iterator();

            while(var5.hasNext()) {
                token = (Token)var5.next();
                tokenCache.remove(token);
            }

        }
    }
}
